﻿namespace OutLook.Module.Load
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using OutLook.Model.Domains;
    using OutLook.Model.Infrastructure;
    using OutLook.Module.Infrastructure;
    using OutLook.Module.Load.Contracts;
    using OutLook.Properties.Calc;
    using OutLook.Module.Infrastructure.Interfaces;
    using System.IO;
    using System.Resources;
    using System.Globalization;

    /// <summary>
    /// Controller for work with load
    /// </summary>
    public class LoadController : DomainControllerBase, ILoadContract
    {
        #region Constructors

        public LoadController(IRepository context)
            : base(context) { }

        #endregion

        #region Properties

        public Load CurrentLoad
        {
            get { return m_CurrentLoad; }

            set { m_CurrentLoad = value; }
        }

        public string CurrentLoadFileName
        {
            get { return m_LoadFileName; }
        }

        public DataTable GetLoadAtTable
        {
            get
            {
                ResourceManager rm = new ResourceManager(typeof(OutLook.Model.Domains.ResourceInformation.ChargeNames));

                DataTable result = new DataTable();
                SetWeightForZ();
                List<string> elements = GetAllChemicalСombinationsInAllCharges();

                ///Columns
                if (CultureInfo.CurrentUICulture.Name == "ru-RU")
                {
                    result.Columns.Add(Constants.ROW_NUMBER, typeof(string));
                    result.Columns.Add("Наименование шихты", typeof(string));
                    result.Columns.Add("Вес (тонны)", typeof(double));
                    foreach (string element in elements)
                    {
                        result.Columns.Add(element+", %", typeof(double));
                    }
                    result.Columns.Add("Влага", typeof(double));
                    result.Columns.Add("Вынос", typeof(double));
                }
                else
                {
                    result.Columns.Add(Constants.ROW_NUMBER, typeof(string));
                    result.Columns.Add(Constants.CHARGE_NAME, typeof(string));
                    result.Columns.Add(Constants.CHARGE_WEIGHT, typeof(double));

                    foreach (string element in elements)
                    {
                        result.Columns.Add(element+", %", typeof(double));
                    }
                    result.Columns.Add(Constants.CHARGE_Z, typeof(double));
                    result.Columns.Add(Constants.CHARGE_WET, typeof(double));
                    result.Columns.Add(Constants.CHARGE_VOLATILES, typeof(double));
                }

                ///Rows
                for (int i = 0; i < m_CurrentLoad.LoadInfo.ChargeToLoad.Count; i++)
                {
                    object[] chargeInRow = new object[result.Columns.Count];
                    chargeInRow[0] = i + 1;
                    chargeInRow[1] = m_CurrentLoad.LoadInfo.ChargeToLoad[i].ChargeRow.Title;
                    chargeInRow[2] = m_CurrentLoad.LoadInfo.ChargeToLoad[i].Weight;
                    for (int j = 0; j < elements.Count; j++)
                    {
                        chargeInRow[j + 3] = 0.0d;
                        for (int k = 0; k < m_CurrentLoad.LoadInfo.ChargeToLoad[i].ChargeRow.Compositions.Count; k++)
                        {
                            if (m_CurrentLoad.LoadInfo.ChargeToLoad[i].ChargeRow.Compositions[k].Element.Equals(elements[j]))
                            {
                                chargeInRow[j + 3] = m_CurrentLoad.LoadInfo.ChargeToLoad[i].ChargeRow.Compositions[k].Percentage;
                            }
                        }
                    }
                    chargeInRow[result.Columns.Count - 3] = m_CurrentLoad.LoadInfo.ChargeToLoad[i].ChargeRow.Z;
                    chargeInRow[result.Columns.Count - 2] = m_CurrentLoad.LoadInfo.ChargeToLoad[i].ChargeRow.Wet;
                    chargeInRow[result.Columns.Count - 1] = m_CurrentLoad.LoadInfo.ChargeToLoad[i].ChargeRow.Volatiles;
                    result.Rows.Add(chargeInRow);
                }

                return result;
            }
        }

        #endregion

        #region DomainControllerBase members

        protected override void Dispose(bool dispoceManged)
        {
            if (m_Disposed)
                return;

            m_Disposed = true;
        }

        #endregion

        #region ILoadContract Implementation

        public DataTable DownloadTheLoad(string fileName)
        {
            m_CurrentLoad = new Load(DataSerializerHelper.XmlRead<LoadData>(fileName));
            m_LoadFileName = fileName;

            return GetLoadAtTable;
        }


        public DataTable ChargeIndicators()
        {
            if (m_CurrentLoad == null)
                return null;

            DataTable result = new DataTable();
            ///Columns
            if (CultureInfo.CurrentUICulture.Name == "ru-RU")
            {
                result.Columns.Add("Тип веса", typeof(string));
            }
            else
            {
                result.Columns.Add(Constants.WEIGHT_TYPE, typeof(string));
            }
            CalcTotalLoadWeight();
            foreach (ChemicalСombination element in m_CurrentLoad.TotalLoadChargeChemicalElements)
            {
                result.Columns.Add(element.Element, typeof(double));
            }

            ///Rows           
            object[][] chargeInRow = new object[2][];
            chargeInRow[0] = new object[result.Columns.Count];
            chargeInRow[1] = new object[result.Columns.Count];
            if (CultureInfo.CurrentUICulture.Name == "ru-RU")
            {
                chargeInRow[0][0] = "Тонны";
            }
            else
            {
                chargeInRow[0][0] = Constants.TONS;
            }
            chargeInRow[1][0] = Constants.PERCENTAGE;
            for (int j = 0; j < m_CurrentLoad.TotalLoadChargeChemicalElements.Count; j++)
            {
                chargeInRow[0][j + 1] = m_CurrentLoad.TotalLoadChargeChemicalElements[j].Weight;
                chargeInRow[1][j + 1] = m_CurrentLoad.TotalLoadChargeChemicalElements[j].Percentage;
            }
            result.Rows.Add(chargeInRow[0]);
            result.Rows.Add(chargeInRow[1]);

            return result;
        }

        public List<string> GetAllChemicalСombinationsInAllCharges()
        {
            if (m_CurrentLoad == null)
                return null;

            List<string> allCompositions = new List<string>();
            foreach (ChargeRowToLoad charge in m_CurrentLoad.LoadInfo.ChargeToLoad)
            {
                foreach (ChemicalСombination comp in charge.ChargeRow.Compositions)
                {
                    allCompositions.Add(comp.Element);
                }
            }

            var elements = allCompositions.Select(element => element).Distinct().OrderBy(el => el).ToList();

            return elements;
        }

        public void SetWeightForZ()
        {
            if (m_CurrentLoad == null)
                return;

            foreach (ChargeRowToLoad item in m_CurrentLoad.LoadInfo.ChargeToLoad)
            {
                if (item.ChargeRow.Z != default(double))
                {
                    ChargeRowToLoad aRow = m_CurrentLoad.LoadInfo.ChargeToLoad.Select(chargeRow => chargeRow).Where(chargeRow => chargeRow.ChargeRow.Title.Equals(Constants.CHARGE_START_A + item.ChargeRow.Title)).First();

                    if (aRow == null)
                        throw new ArgumentException();

                    aRow.Weight = Math.Round((item.Weight * item.ChargeRow.Z * (1 - item.ChargeRow.Wet / 100 - item.ChargeRow.Volatiles / 100)) / 100, 2);
                }

            }
        }

        public DataTable ChargeProperties()
        {
            if (m_CurrentLoad == null)
                return null;

            DataTable result = new DataTable();
            ///Columns
            result.Columns.Add(string.Concat(Constants.ELEMENT_FE2O3, Constants.PERCENTAGE_IN_BUSCKETS), typeof(double));
            result.Columns.Add(string.Concat(Constants.ELEMENT_FE, Constants.PERCENTAGE_IN_BUSCKETS), typeof(double));
            result.Columns.Add(Constants.ORE_CAPACITY, typeof(double));
            result.Columns.Add(string.Concat(Constants.ELEMENT_CaO, Constants.DIV, Constants.ELEMENT_SiO2), typeof(double));
            result.Columns.Add(string.Concat(Constants.OPEN_BUSCKET, Constants.ELEMENT_CaO, Constants.PLUS, Constants.ELEMENT_MgO, Constants.CLOSE_BUSCKET, Constants.DIV, Constants.ELEMENT_SiO2), typeof(double));
            result.Columns.Add(string.Concat(Constants.ELEMENT_Al2O3, Constants.DIV, Constants.ELEMENT_MgO), typeof(double));
            result.Columns.Add(Constants.De, typeof(double));
            result.Columns.Add(Constants.Ro, typeof(double));

            CalcLoadProperties();

            ///Rows           
            object[] chargeInRow = new object[8];
            chargeInRow[0] = m_CurrentLoad.Fe2O3;
            chargeInRow[1] = m_CurrentLoad.TotalFe;
            chargeInRow[2] = Math.Round(m_CurrentLoad.OreCapacity, Constants.NUMBER_ROUND);
            chargeInRow[3] = m_CurrentLoad.Basic1;
            chargeInRow[4] = m_CurrentLoad.Basic2;
            chargeInRow[5] = m_CurrentLoad.Basic3;
            chargeInRow[6] = m_CurrentLoad.De;
            chargeInRow[7] = m_CurrentLoad.Ro;
            result.Rows.Add(chargeInRow);

            return result;
        }

        /// <summary>
        /// Calculation of Total Weight of each chemical composition in Load for charge
        /// and sets it into properties TotalLoadChargeChemicalElements and TotalLoadWeight
        /// </summary>
        public void CalcTotalLoadChargeWeight()
        {
            List<string> elements = GetAllChemicalСombinationsInAllCharges();
            m_CurrentLoad.TotalLoadChargeChemicalElements = new List<ChemicalСombination>();

            foreach (string element in elements)
            {
                double ElementsWeigth = 0;
                foreach (ChargeRowToLoad item in m_CurrentLoad.LoadInfo.ChargeToLoad)
                {
                    item.WeightCalculation();
                    foreach (ChemicalСombination ItemWeigth in item.ChargeRow.Compositions)
                    {
                        if (ItemWeigth.Element == element)
                        {
                            ElementsWeigth = ElementsWeigth + ItemWeigth.Weight;
                        }
                    }
                }
                ChemicalСombination temp = new ChemicalСombination(element, 0);
                temp.Weight = Math.Round(ElementsWeigth, 2);
                m_CurrentLoad.TotalLoadChargeChemicalElements.Add(temp);
            }
        }

        /// <summary>
        /// Calculation of Total Load Weight and set percentage of each element in charges
        /// </summary>
        public void CalcTotalLoadWeight()
        {
            if (m_CurrentLoad.TotalLoadChargeChemicalElements == null)
                CalcTotalLoadChargeWeight();

            var RezListComp = from item in m_CurrentLoad.TotalLoadChargeChemicalElements
                              where (item.Element.Contains(Constants.ELEMENT_FE) && !item.Element.Equals(Constants.ELEMENT_FE2O3))
                              orderby item.Element
                              select item;

            double Fe = 0;
            double Femet = 0;
            double FeO = 0;

            foreach (ChemicalСombination item in RezListComp)
            {
                if (item.Element == Constants.ELEMENT_FE)
                {
                    Fe = item.Weight;
                }
                if (item.Element == Constants.ELEMENT_FEMET)
                {
                    Femet = item.Weight;
                }
                if (item.Element == Constants.ELEMENT_FEO)
                {
                    FeO = item.Weight;
                }
            }

            m_CurrentLoad.Fe2O3 = ((Fe - Femet - FeO * 55.847 / 71.847)) * 159.694 / 111.694;


            var tempTotalLoadWeight = (from item in m_CurrentLoad.TotalLoadChargeChemicalElements
                                       where (!item.Element.Contains(Constants.ELEMENT_FE))
                                       select item.Weight).Sum();


            m_CurrentLoad.TotalLoadWeight = Math.Round(tempTotalLoadWeight + m_CurrentLoad.Fe2O3 + Femet + FeO, 2);

            foreach (ChemicalСombination item in m_CurrentLoad.TotalLoadChargeChemicalElements)
            {
                item.Percentage = Math.Round((item.Weight / m_CurrentLoad.TotalLoadWeight) * 100, 2);
            }
        }

        /// <summary>
        /// Calculation load properties: FeTotal, De, Ro, Dde, CaO/SiO2, Al2O3/MgO, (CaO+MgO)/SiO2, OreCapacity
        /// </summary>
        public void CalcLoadProperties()
        {
            if (m_CurrentLoad.TotalLoadWeight == default(double))
                CalcTotalLoadWeight();


            var CokeWeight = (from item in m_CurrentLoad.LoadInfo.ChargeToLoad
                              where Constants.COKE.Contains(item.ChargeRow.Title)
                              select item).First();

            double ChargeWeightCoke = CokeWeight.Weight * (1 - CokeWeight.ChargeRow.Volatiles / 100 - CokeWeight.ChargeRow.Wet / 100);

            var ChargeWithoutCoke = from item in m_CurrentLoad.LoadInfo.ChargeToLoad
                                    where !Constants.COKE.Contains(item.ChargeRow.Title) && !Constants.ACOKE.Contains(item.ChargeRow.Title)
                                    select item;

            double ChargeWeightWithoutCoke = 0;
            foreach (var item in ChargeWithoutCoke)
            {
                ChargeWeightWithoutCoke = ChargeWeightWithoutCoke + item.Weight * (1 - item.ChargeRow.Volatiles / 100 - item.ChargeRow.Wet / 100);
            }

            m_CurrentLoad.OreCapacity = ChargeWeightWithoutCoke / ChargeWeightCoke;

            CalcLoadChemicalParametrs();

            foreach (ChemicalСombination item in m_CurrentLoad.TotalLoadChargeChemicalElements)
            {
                if (item.Element == "Fe")
                {
                    m_CurrentLoad.TotalFe = item.Percentage;
                }
            }

            m_CurrentLoad.Fe2O3 = Math.Round((m_CurrentLoad.Fe2O3 / m_CurrentLoad.TotalLoadWeight) * 100, 2);

            double CaO = (from item in m_CurrentLoad.TotalLoadChargeChemicalElements
                          where item.Element == "CaO"
                          select item.Percentage).First();

            double SiO2 = (from item in m_CurrentLoad.TotalLoadChargeChemicalElements
                           where item.Element == "SiO2"
                           select item.Percentage).First();

            if (SiO2 != 0)
            {
                m_CurrentLoad.Basic1 = Math.Round(CaO / SiO2, 3);
            }


            double MgO = (from item in m_CurrentLoad.TotalLoadChargeChemicalElements
                          where item.Element == "MgO"
                          select item.Percentage).First();

            if (SiO2 != 0)
            {
                m_CurrentLoad.Basic2 = Math.Round((CaO + MgO) / SiO2, 3);
            }

            double Al2O3 = (from item in m_CurrentLoad.TotalLoadChargeChemicalElements
                            where item.Element == "Al2O3"
                            select item.Percentage).First();

            if (MgO != 0)
            {
                m_CurrentLoad.Basic3 = Math.Round(Al2O3 / MgO, 3);
            }
        }

        /// <summary>
        /// Calculation chemical parametrs of load: de, ro
        /// </summary>
        public void CalcLoadChemicalParametrs()
        {
            List<Coupla> temp = new List<Coupla>();

            var LoadToSlagSystem = from item in m_CurrentLoad.TotalLoadChargeChemicalElements
                                   where !item.Element.StartsWith("Fe")
                                   select new { Element = item.Element, Percentage = item.Percentage };

            foreach (var item in LoadToSlagSystem)
            {
                Coupla tmp = Coupla.Create(item.Element, item.Percentage);
                temp.Add(tmp);
            }

            var FeOToSlagSystem = (from item in m_CurrentLoad.TotalLoadChargeChemicalElements
                                   where item.Element == "FeO"
                                   select new { Element = item.Element, Percentage = item.Percentage }).First();

            Coupla FeOtmp = Coupla.Create(FeOToSlagSystem.Element, FeOToSlagSystem.Percentage);
            temp.Add(FeOtmp);

            SlagSystem slagsystem = new SlagSystem(temp);
            slagsystem.CalcSlagSystemProperties();

            foreach (Coupla item in slagsystem.slagProperties)
            {
                if (item.Indicator == "Ro")
                {
                    m_CurrentLoad.Ro = Math.Round(item.Value, 3);
                }
                if (item.Indicator == "De")
                {
                    m_CurrentLoad.De = Math.Round(item.Value, 3);
                }
            }

        }

        /// <summary>
        /// Calculate the coke consumption
        /// </summary>
        /// <param name="Consumption">given the consumption of coke</param>
        /// <param name="IronContent">given the iron content in percent</param>
        /// <returns></returns>
        public double CalculationOfCoke(float Consumption, float IronContent)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        ///  Calculate the given material amount
        /// </summary>
        /// <param name="title">title of the given material</param>
        /// <returns></returns>
        public double CalculationOfAmountOfMaterial(string title)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Calculation for a given basic slag
        /// </summary>
        /// <param name="fe">given the iron content in the iron</param>
        /// <param name="si">given the silicon content in the iron</param>
        /// <param name="basic">given the basic slag</param>
        /// <returns></returns>
        public double CalculationForGivenBasicSlag(float fe, float si, float basic)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Fields

        private bool m_Disposed = false;
        private Load m_CurrentLoad = null;
        private string m_LoadFileName = null;

        #endregion

    }
}
